package org.aldar.bquest.logic;

import android.content.Intent;
import android.os.Message;
import android.util.Log;
import org.aldar.bquest.constants.GameCycleState;
import org.aldar.bquest.constants.IConstants;
import org.aldar.bquest.logic.controller.board.AfterMatchProcessor;
import org.aldar.bquest.logic.controller.board.AvailableMovesCounter;
import org.aldar.bquest.logic.controller.board.TouchAndMoveController;
import org.aldar.bquest.logic.controller.entity.TileBoard;
import org.aldar.bquest.logic.controller.level.LevelController;
import org.aldar.bquest.resources.ResourceManager;
import org.aldar.bquest.screens.LevelFailedScreen;
import org.aldar.bquest.screens.MainBoardScreen;
import org.aldar.bquest.util.Logger;
import org.aldar.bquest.util.ScoreCounter;
import org.andengine.engine.handler.IUpdateHandler;
import org.andengine.engine.handler.timer.ITimerCallback;
import org.andengine.engine.handler.timer.TimerHandler;
import org.andengine.opengl.texture.ITexture;

import java.io.File;
import java.util.Date;

/**
 * User: Daria
 * Date: 4/14/13 10:24 PM
 */
public class TilesGameCycle implements IConstants, IUpdateHandler {

    private boolean mGameRunning;

    private GameCycleState STATE = GameCycleState.CHECK;

    private GameCycleState oldState = GameCycleState.CHECK;

    private static GameCycleState lastMove = GameCycleState.MOVE_DOWN;

    private static TilesGameCycle instance;

    private long prevStatusMillis = 0;

    private boolean availableMovesCounted = false;
    private boolean afterTexturesLoaded = false;
    private boolean touchLockChecked = false;

    private long timePassedFromWaitingSwap = 0;

    private float curTime = 0;

    private static final Logger LOG = new Logger(TilesGameCycle.class);

    private TilesGameCycle() {
    }

    public static TilesGameCycle getInstance() {
        if (instance == null) {
            instance = new TilesGameCycle();
        }
        return instance;
    }

    public static GameCycleState getLastMove() {
        //LOG.i("LAST MOVE got: " + lastMove);
        return lastMove;
    }

    public static void setLastMove(GameCycleState lastMove) {
        //LOG.i("LAST MOVE set: " + lastMove);
        TilesGameCycle.lastMove = lastMove;
    }

    @Override
    public void reset() {
    }

    @Override
    public void onUpdate(float pSecondsElapsed) {
        curTime += pSecondsElapsed;
        long millis1 = new Date().getTime();
        GameCycleState state1 = STATE;
        /*
        TestUtil.getInstance().updateText("killedKeys", AfterMatchProcessor.killedKeys.size() + "");
        TestUtil.getInstance().updateText("timeline.isLevelFinished", "" + LevelController.getTimeLine().isLevelFinished());
        TestUtil.getInstance().updateText("tilesInAction", TileBoard.tilesInAction.size() + "");
        TestUtil.getInstance().updateText("tilesToRefill", AfterMatchProcessor.tilesToRefill + "");
                                                                    */
        if (mGameRunning) {
            switch (STATE) {
                case WAITING_SWAP:
                    //int availableMoves = AvailableMovesCounter.checkAvailableMoves();
                    if (LevelController.getCurrentLevelState() == LevelController.LevelState.PROGRESS && new Date().getTime() - prevStatusMillis > 100 && availableMovesCounted == false) {
                        //TilesPool.printCount();
                        //printMemory();
                        int availableMoves = AvailableMovesCounter.checkAvailableMoves();
                        //int availableMoves = 1;
                        LOG.i("loony available moves = " + availableMoves);
                        if (availableMoves <= 0) {
                            TilesGameCycle.getInstance().setState(GameCycleState.WAITING);
                            TileBoard.recreateHopelessTileBoard();
                            MainBoardScreen.getScm().getMainScene().registerUpdateHandler(new TimerHandler(0.1f, new ITimerCallback() {
                                @Override
                                public void onTimePassed(TimerHandler pTimerHandler) {
                                    MainBoardScreen.getInstance().getGameSound().setLowMainLoopVolume();
                                    MainBoardScreen.getInstance().getGameSound().playNoMovesLeftSound();
                                }
                            }));
                            MainBoardScreen.getScm().getMainScene().registerUpdateHandler(new TimerHandler(2f, new ITimerCallback() {
                                @Override
                                public void onTimePassed(TimerHandler pTimerHandler) {
                                    MainBoardScreen.getInstance().getGameSound().setDefaultMainLoopVolume();
                                }
                            }));

                        }
                        availableMovesCounted = true;
                    }
                    if (LevelController.getCurrentLevelState() == LevelController.LevelState.PROGRESS
                            && new Date().getTime() - prevStatusMillis > 5000
                            && touchLockChecked == false) {
                        if (TouchAndMoveController.ILLEGAL_TOUCH == true) {
                            LOG.i("WARNING touch lock found on WAITING_SWAP after 5 sec!!! forcing unlock");
                            TouchAndMoveController.resetLocks();
                        }

                    }
                    if (new Date().getTime() - prevStatusMillis > 1000 && afterTexturesLoaded == false) {
                        for (int i = 0; i < 3; i++) {
                            if (ResourceManager.getInstance().getAfterLoadTextures().size() > 0) {
                                ITexture texture = ResourceManager.getInstance().getAfterLoadTextures().get(0);
                                String textureName = ResourceManager.getInstance().getAfterLoadTextureNames().get(0);
                                MainBoardScreen.getInstanceEngine().getTextureManager().loadTexture(texture);
                                LOG.i("Loaded afterLoad texture, filename: " + textureName);

                                ResourceManager.getInstance().getAfterLoadTextures().remove(0);
                                ResourceManager.getInstance().getAfterLoadTextureNames().remove(0);
                            }
                        }
                        afterTexturesLoaded = true;
                    }
                    break;
                case SWAP_TILES:
                    TilesGameCycle.getInstance().setState(GameCycleState.WAITING);
                    TouchAndMoveController.swapTiles();
                    break;
                case SWAP_FINISHED:
                    TilesGameCycle.getInstance().setState(GameCycleState.WAITING);
                    TouchAndMoveController.onSwapFinished();
                    break;
                case BACK_SWAP_FINISHED:
                    TilesGameCycle.getInstance().setState(GameCycleState.WAITING);
                    TouchAndMoveController.onBackSwapFinished();
                    break;
                case CHECK:
                    TilesGameCycle.getInstance().setState(GameCycleState.WAITING);
                    AfterMatchProcessor.removeMatchedTiles(); //水平消去
                    break;
                default:
                    break;
            }
        }
        long millis2 = new Date().getTime();
        if (millis2 - millis1 > 10)
            LOG.i("Status: " + state1.name() + " --> " + STATE.name() + ", Update too long ms: " + (millis2 - millis1));
    }

    public void goToLevelFailedScreen() {
        Intent intent = new Intent();
        intent.setClass(MainBoardScreen.screenInstance.getApplicationContext(), LevelFailedScreen.class);
        MainBoardScreen.screenInstance.startActivity(intent);
        MainBoardScreen.screenInstance.finish();
    }

    public void onGameOver() {
        mGameRunning = false;
        if (ScoreCounter.getInstance().getScore() > 0) {
            Message message = new Message();
            message.what = 0;
            //handler.sendMessage(message);
        } else {
            //toMenuView();
        }
    }

    public boolean isGameRunning() {
        return mGameRunning;
    }

    public void setGameRunning(boolean mGameRunning) {
        this.mGameRunning = mGameRunning;
    }

    public GameCycleState getState() {
        return STATE;
    }

    public void setState(GameCycleState state) {
        oldState = STATE;
        StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
        STATE = state;
        long curMillis = new Date().getTime();
        long millisElapsed = curMillis - prevStatusMillis;
        LOG.i("jewel", millisElapsed + " Status change ms: " + state + ", caller: " + stackTraceElements[3].getClassName() +
                "." + stackTraceElements[3].getMethodName() +
                " line " + stackTraceElements[3].getLineNumber());/*
        TestUtil.getInstance().updateText("gstate", state.name() + "was " + oldState + " " + stackTraceElements[3].getClassName().substring(35) +
                "." + stackTraceElements[3].getMethodName() +
                " ln " + stackTraceElements[3].getLineNumber());
        */
        prevStatusMillis = curMillis;
        availableMovesCounted = false;
        afterTexturesLoaded = false;
        touchLockChecked = false;
    }

    public void resetToWaitingSwap() {
        if (LevelController.getCurrentLevelState() == LevelController.LevelState.FAILED) {
            LevelController.getInstance().setCurrentLevelState(LevelController.LevelState.NONE);
            LevelController.getInstance().onLevelFailed();
        }
        if (TileBoard.getSourceTile() != null) {
            TileBoard.getSourceTile().setInMovement(false);
            TileBoard.getSourceTile().setIsInDrag(false);
            TileBoard.getSourceTile().restartAnimation();
        }
        if (getState() != GameCycleState.WAITING_SWAP) {
            //moved here from onUpdate to prevent multiple unlocking...
            TouchAndMoveController.DONT_TOUCH = false;
            TouchAndMoveController.unlockTouchActions();
            //TouchAndMoveController.ILLEGAL_TOUCH = false;
            setState(GameCycleState.WAITING_SWAP);
            AfterMatchProcessor.firstMatchWasCrystal = false;
            AfterMatchProcessor.firstMatchWasCurrentLandscape = false;
            AfterMatchProcessor.matchSequence = 0;
        }
    }


    private void printMemory() {
        /* Total number of processors or cores available to the JVM */
        Log.i("aldar", "Available processors (cores): " +
                Runtime.getRuntime().availableProcessors());

  /* Total amount of free memory available to the JVM */
        Log.i("aldar", "Free memory (bytes): " +
                Runtime.getRuntime().freeMemory());

  /* This will return Long.MAX_VALUE if there is no preset limit */
        long maxMemory = Runtime.getRuntime().maxMemory();
  /* Maximum amount of memory the JVM will attempt to use */
        Log.i("aldar", "Maximum memory (bytes): " +
                (maxMemory == Long.MAX_VALUE ? "no limit" : maxMemory));

  /* Total memory currently in use by the JVM */
        Log.i("aldar", "Total memory (bytes): " +
                Runtime.getRuntime().totalMemory());

  /* Get a list of all filesystem roots on this system */
        File[] roots = File.listRoots();

  /* For each filesystem root, print some info */
        for (File root : roots) {
            Log.i("aldar", "File system root: " + root.getAbsolutePath());
            Log.i("aldar", "Total space (bytes): " + root.getTotalSpace());
            Log.i("aldar", "Free space (bytes): " + root.getFreeSpace());
            Log.i("aldar", "Usable space (bytes): " + root.getUsableSpace());
        }
    }

}
